#include "utils.h"

char ** split(char* chaine, char *delim){
        
        int nb_elem = 1;
        int pos = 0;
        char** split;
        split = malloc(nb_elem* sizeof(char*));


        char* chaineTmp;
        chaineTmp = malloc((strlen(chaine)+1)*sizeof(char));
        memcpy(chaineTmp,chaine,strlen(chaine)+1);

        char * elem;
        elem = strtok (chaineTmp,delim);
        while (elem != NULL)
        {
          if(pos+1 > nb_elem) {
                nb_elem++;
                split = (char**)realloc(split,nb_elem*sizeof(char*));
          }
          split[pos] = malloc((strlen(elem)+1) * sizeof(char));
          memcpy(split[pos],elem,strlen(elem)+1);
          elem = strtok (NULL, delim);
          pos++;
        }
        split = (char**)realloc(split,(nb_elem+1)*sizeof(char*));
        split[pos] = NULL;

  free(chaineTmp);
  return split;
}


char * reverse_split (char ** str){
        char* reverse;
        asprintf(&reverse, "%s%c%s%c%s%c%s%c", str[0], '|', str[1], '|', str[2], '|', str[3], '|');

        return reverse;
}


void saveKey(char* key, int taille){
  FILE* fichier = fopen("key", "w+");

  char* key64;
  int tailleMalloc = (taille/3)*4+9;

  key64 = (char *) malloc(tailleMalloc * sizeof(char));
  b64_encode(key, key64, taille);
  key64[tailleMalloc - 1]='\0';
  
  if(fichier!=NULL){
    fputs(key64, fichier);
    fclose(fichier);
  }else{
    printf("Impossible d'ouvrir le fichier key pour écriture!\n");
  }
 free(key64);
}

char* readKey(){
  FILE* fichier = fopen("key", "r");  
  char key64[256];

 if(fichier!=NULL){
    fgets(key64, 256, fichier);
    fclose(fichier);
  }else{
    printf("Impossible d'ouvrir le fichier key pour lecture!\n");
    return NULL;
  }
  
  int tailleMalloc = strlen(key64)+1;
  char* key = (char *) malloc (tailleMalloc * sizeof (char));
  int tailleKey = b64_decode(key64, key);
  key = realloc(key, tailleKey + 1);
  key[tailleKey]='\0';

  return key;
}



int
b64_encode(unsigned char *in, char *out, int in_len){
    static const char b64[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    unsigned i_bits = 0;
    int i_shift = 0;
    int bytes_remaining = in_len;

    char *dst = out;

    if (in_len) {
        while (bytes_remaining) {
            i_bits = (i_bits << 8) + *in++;
            bytes_remaining--;
            i_shift += 8;

            do {
                *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
                i_shift -= 6;
            } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0));
        }
        while ((dst - out) & 3)
            *dst++ = '=';
    }

    *dst = '\0';

    return(dst - out);
}


int b64_decode(const char *in, unsigned char *out){
    int i, v;
    unsigned char *dst = out;

    v = 0;
    for (i = 0; in[i] && in[i] != '='; i++) {
        unsigned int index= in[i]-43;

        if (index>=(sizeof(map2)/sizeof(map2[0])) || map2[index] == 0xff)
            return(-1);

        v = (v << 6) + map2[index];

        if (i & 3)
            *dst++ = v >> (6 - 2 * (i & 3));
    }

    *dst = '\0';

    return(dst - out);
}

int add_packet(long int ts , unsigned char * hash, int tailleHash){

  time_t t;
  time(&t);

  if(t > ts+RULE_TIMEOUT)
    return 2;

  /* Si la liste est null alors on alloue l'espace */
  if(list == NULL){
    list = (struct List*) malloc(sizeof(struct List));
    struct Window* elem = (struct Window*) malloc(sizeof(struct Window));
    elem->time = ts;
    elem->hash = hash;
    elem->id = idRequest;
        
    elem->suivant = elem;
    list->tete = elem;
    list->nb_elem = 1;
  }
  else{
    /* timestamp périmé? */
    if(ts >= list->tete->suivant->time){
      /* Le paquet est-il rejoué? */
      if(compareHashList(hash, tailleHash)==0){
        struct Window* elem = (struct Window*) malloc(sizeof(struct Window));
        elem->time = ts;
        elem->hash = hash;
        elem->id = idRequest;

        /* Si on a atteint le nb max on suppprime le plus ancien */
        if(list->nb_elem == WINDOW_MAX){
          struct Window* elem_tmp = list->tete->suivant;
          elem->suivant = list->tete->suivant->suivant;
          list->tete->suivant=elem;
	  free(elem_tmp->hash);
          free(elem_tmp);
        }
        else{
          elem->suivant = list->tete->suivant;
          list->nb_elem++;
          list->tete->suivant=elem;
        }
        
        list->tete = elem;
      }
      else
            return 1;
    }
    /* le timestamp est périmé*/
    else
      return 2;
  }

    return 0;
}
  
int compareHashList(unsigned char* hash, int tailleHash){
  int i;
        
  struct Window* elem = list->tete->suivant;

  for(i=0; i<list->nb_elem; i++){
        /*printf("n°%d ",i);
        printf("%.2x ",elem);
        printf("Hash : %.2x ",hash);
        printf("Elem->id : ");
        printf("%d Hash : %.15x \n",elem->id,elem->hash);*/
    if(memcmp(hash, elem->hash, tailleHash) == 0)
      return 1;
    elem=elem->suivant;
        
  }
  return 0;
}

void delPacket(int idPacket){

if(list!=NULL){
        if(list->nb_elem == 1){
                free(list->tete);
                free(list);
                list=NULL;
        }
        else{   
                int i;
                struct Window* elem = list->tete;
                for(i=0; i<list->nb_elem; i++){
                        if(elem->suivant->id == idPacket){
                                struct Window* elem_tmp = elem->suivant;
                                elem->suivant = elem->suivant->suivant;
                                free(elem_tmp);
                                list->nb_elem--;
                        }
                        else
                                elem = elem->suivant;
                }
        }       
        }
}

int size (){
        return list->nb_elem;
}

void addRequest(long int ts, char* ip, char* request){
        
        ajoutRegleEnCours = 1;

        /* Si la liste est null alors on alloue l'espace */
        if(listrequest == NULL){
                listrequest = (struct ListRequest*) malloc(sizeof(struct ListRequest));
                struct Request* req = (struct Request*) malloc(sizeof(struct Request));
                req->time = ts;
                req->id = idRequest;
                req->ip = malloc((strlen(ip)+1)*sizeof(char));
                memcpy(req->ip,ip,strlen(ip)+1);
                req->request = split(request,":");
                req->suivant = NULL;
                listrequest->tete = req;
                
                addIptableRule(req);
        }
        else
        {
                struct Request* req = (struct Request*) malloc(sizeof(struct Request));
                req->time = ts; 
                req->id = idRequest;
                req->ip = malloc((strlen(ip)+1)*sizeof(char));
                memcpy(req->ip,ip,strlen(ip)+1);
                req->request = split(request,":");
                req->suivant = NULL;
                struct Request* elem = listrequest->tete;
                if(elem != NULL)
                {
                        while(elem->suivant != NULL)
                        {
                                elem = elem->suivant;
                        }
                        elem->suivant = req;
                }
                else
                        listrequest->tete = req;
                addIptableRule(req);
        }
        ajoutRegleEnCours = 0;
}

void addIptableRule(struct Request* req)
{
        int i;
        struct tm *temps;
        time_t time = req->time+RULE_TIMEOUT;
        temps = localtime(&time);
        printf("**** Ajout des règles iptables ****\n\n");
        for(i = 0 ; req->request[i] != NULL ; i++)
        {
                char** port = split(req->request[i],"/");
                char* rule;
                asprintf(&rule,"iptables -A INPUT -p %s -s %s --dport %s -m time --datestop $(date +'%d-%d-%d')T$(date +'%d:%d:%d') -j  ACCEPT",port[0],req->ip,port[1],1900+temps->tm_year,temps->tm_mon+1,temps->tm_mday,temps->tm_hour,temps->tm_min,temps->tm_sec);
                printf("%s\n\n",rule);
                system(rule);
                free(rule);
                free(port[0]);
                free(port[1]);
                free(port[2]);
                free(port);
                
        }
        
}

void delIptableRule(struct Request* req)
{
        int i;
        struct tm *temps;
        time_t time = req->time+RULE_TIMEOUT;
        temps = localtime(&time);
        printf("**** Suppression des règles iptables ****\n\n");
        for(i = 0 ; req->request[i] != NULL ; i++)
        {
                char** port = split(req->request[i],"/");
                char* rule;
                asprintf(&rule,"iptables -D INPUT -p %s -s %s --dport %s -m time --datestop $(date +'%d-%d-%d')T$(date +'%d:%d:%d') -j  ACCEPT",port[0],req->ip,port[1],1900+temps->tm_year,temps->tm_mon+1,temps->tm_mday,temps->tm_hour,temps->tm_min,temps->tm_sec);
                printf("%s\n\n",rule);
                system(rule);
                free(rule);
                free(port[0]);
                free(port[1]);
                free(port[2]);
                free(port);
        }
}

